﻿using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using ST.Buz.Base;
using ST.Buz.Base.Entity;
using ST.Buz.Base.Enums;
using ST.Buz.Base.ViewModel;
using ST.Common.Util;
using ST.Common.Util.Model;
using ST.Common.Util.Mvc;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

namespace ST.Buz.Service
{
	/// <summary>
	/// 只针对当前项目的扩展接口定义
	/// </summary>
	public partial interface IServiceMachining
	{
		PageData GetPageList(VMS_BJG_Machining searchModel, UserSession sessionCurrent);

		BJG_Machining GetViewDetail(int id, UserSession sessionCurrent, bool deattached = true);

		BJG_Machining GetEditDetail(int id, UserSession sessionCurrent);

		int AddOrUpdate(BJG_Machining model, UserSession sessionCurrent);

		void AddOrUpdateWithinTrans(BJG_Machining model, UserSession sessionCurrent);

		bool Delete(int id, UserSession sessionCurrent);

		bool BatchDelete(int[] ids, UserSession sessionCurrent);

		string NextSNo();
	}

	/// <summary>
	/// 只针对当前项目的扩展接口实现
	/// </summary>
	public partial class ServiceMachining
	{
		private readonly IServiceSysLog serviceSysLog;
		private readonly IServiceFinanceRecvDue serviceFinanceRecvDue;
		private readonly IServiceFinanceRecv serviceFinanceRecv;

		public ServiceMachining(BuzContext ctx,
			IServiceSysLog _serviceSysLog,
			IServiceFinanceRecvDue _serviceFinanceRecvDue,
			IServiceFinanceRecv _serviceFinanceRecv,
			ILogger<ServiceMachining> log)
		{
			serviceSysLog = _serviceSysLog;
			serviceFinanceRecvDue = _serviceFinanceRecvDue;
			serviceFinanceRecv = _serviceFinanceRecv;

			context = ctx;
			logger = log;
		}

		private IQueryable<BJG_Machining> GetQuery(VMS_BJG_Machining searchModel, UserSession sessionCurrent)
		{
			var query = from m in context.Machining
						join cat in context.SysEnumCode on m.MachiningType.ToString() equals cat.Value into cattmp
						from catall in cattmp.DefaultIfEmpty()
						select new BJG_Machining
						{
							ID = m.ID,
							SNo = m.SNo,
							MachiningType = m.MachiningType,
							MachiningTypeText = catall.Name,
							PartnerID = m.PartnerID,
							PartnerName = m.PartnerName,
							DeliveryDate = m.DeliveryDate,
							DeliveryMan = m.DeliveryMan,
							DeliveryPhone = m.DeliveryPhone,
							Rolls = m.Rolls,
							Meters = m.Meters,
							Price = m.Price,
							Total = m.Total,
							StateNow = m.StateNow,
							RecvType = m.RecvType,
							RecvWay = m.RecvWay,
							PreRecvTotal = m.PreRecvTotal,
							Comment = m.Comment,
							AddDate = m.AddDate,
							AddManID = m.AddManID,
							AddManName = m.AddManName,
							OrgID = m.OrgID,
						};
			if (!string.IsNullOrWhiteSpace(searchModel.sno))
			{
				query = query.Where(m => m.SNo.Contains(searchModel.sno));
			}
			if (searchModel.machiningtype.HasValue && searchModel.machiningtype.Value > 0)
			{
				query = query.Where(m => m.MachiningType == searchModel.machiningtype.Value);
			}
			if (searchModel.partnerid.HasValue && searchModel.partnerid.Value > 0)
			{
				query = query.Where(m => m.PartnerID == searchModel.partnerid.Value);
			}
			else if (!string.IsNullOrWhiteSpace(searchModel.partnername))
			{
				query = query.Where(m => EF.Functions.Like(m.PartnerName, "%" + searchModel.partnername + "%"));
			}
			else if (!string.IsNullOrWhiteSpace(searchModel.deliveryman))
			{
				query = query.Where(m => EF.Functions.Like(m.DeliveryMan, "%" + searchModel.deliveryman + "%"));
			}
			if (searchModel.date_s != DateTime.MinValue)
			{
				query = query.Where(m => m.DeliveryDate >= searchModel.date_s);
			}
			if (searchModel.date_e != DateTime.MinValue)
			{
				query = query.Where(m => m.DeliveryDate < searchModel.date_e.AddDays(1));
			}
			if (searchModel.state != null && searchModel.state.Length > 0)
			{
				query = searchModel.state.Length == 1 ? query.Where(m => m.StateNow == searchModel.state[0]) : query.Where(m => searchModel.state.Contains(m.StateNow));
			}
			if (searchModel.orgids != null && searchModel.orgids.Length > 0)
			{
				query = searchModel.orgids.Length == 1 ? query.Where(m => m.OrgID == searchModel.orgids[0]) : query.Where(m => searchModel.orgids.Contains(m.OrgID));
			}
			return query;
		}

		/// <summary>
		/// 分页列表
		/// </summary>
		public PageData GetPageList(VMS_BJG_Machining searchModel, UserSession sessionCurrent)
		{
			PageData result = null;
			try
			{
				searchModel.Validate();

				var query = GetQuery(searchModel, sessionCurrent);
				var sumCol = new string[] { "Rolls", "Meters", "Total", "PreRecvTotal" };
				object[] sumTotal = null;
				var sumResult = (from q in query
								 select new
								 {
									 Rolls = query.Sum(m => m.Rolls),
									 Meters = query.Sum(m => m.Meters),
									 Total = query.Sum(m => m.Total),
									 PreRecvTotal = query.Sum(m => m.PreRecvTotal),
								 }).FirstOrDefault();
				if (sumResult == null)
				{
					sumTotal = new object[] { 0M, 0M, 0M, 0M };
				}
				else
				{
					sumTotal = new object[] {
						sumResult.Rolls,
						sumResult.Meters,
						sumResult.Total,
						sumResult.PreRecvTotal,
					};
				}
				switch (searchModel.sortby)
				{
					default:
						query = searchModel.orderby == Common.Util.Mvc.SortOrder.Ascending ? query.OrderBy(e => e.ID) : query.OrderByDescending(e => e.ID);
						break;
				}
				result = new PageData(searchModel.pnum.Value, searchModel.psize.Value);
				result.Load(query);
				result.sumtotal = sumTotal;
				result.sumcol = sumCol;
			}
			catch (ArgumentNullException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.Message, ex);
			}
			return result;
		}

		/// <summary>
		/// 获取详细信息
		/// </summary>
		/// <param name="id"></param>
		/// <param name="sessionCurrent"></param>
		/// <returns></returns>
		public BJG_Machining GetViewDetail(int id, UserSession sessionCurrent, bool deattached = true)
		{
			BJG_Machining model = null;
			try
			{
				model = Get(id);
				if (model == null)
				{
					throw new EntityNotFoundException("未找到id为" + id + "的记录");
				}
			}
			catch (ArgumentNullException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (EntityNotFoundException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.Message, ex);
			}
			return model;
		}

		/// <summary>
		/// 获取详细信息
		/// </summary>
		/// <param name="id"></param>
		/// <param name="sessionCurrent"></param>
		/// <returns></returns>
		public BJG_Machining GetEditDetail(int id, UserSession sessionCurrent)
		{
			return GetViewDetail(id, sessionCurrent);
		}

		/// <summary>
		/// 新增或修改保存
		/// </summary>
		public int AddOrUpdate(BJG_Machining model, UserSession sessionCurrent)
		{
			try
			{
				if (model == null)
				{
					throw new ArgumentNullException("model");
				}

				if (sessionCurrent == null)
				{
					throw new ArgumentNullException("sessionCurrent");
				}

				using (var trans = context.Database.BeginTransaction())
				{
					try
					{
						#region 事务具体操作
						AddOrUpdateWithinTrans(model, sessionCurrent);
						#endregion

						trans.Commit();

						return model.ID;
					}
					catch (Exception ex)
					{
						trans.Rollback();
						throw ex.InnerException ?? ex;
					}
				}
			}
			catch (ArgumentNullException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.InnerException != null ? ex.InnerException.Message : ex.Message, ex);
			}
		}

		/// <summary>
		/// 事务内新增或修改
		/// </summary>
		/// <param name="model"></param>
		/// <param name="sessionCurrent"></param>
		public void AddOrUpdateWithinTrans(BJG_Machining model, UserSession sessionCurrent)
		{
			DateTime dtNow = DateTime.Now;
			string ip = GetRequestIP();


			if (model.ID > 0)
			{
				var modelOld = Get(model.ID, true);
				Update(model);

				#region 直接删除应收款
				context.Database.ExecuteSqlRaw("DELETE FROM IMS_FinanceRecv WHERE ID IN(SELECT rd.RecvID FROM IMS_FinanceRecvDetail rd INNER JOIN IMS_FinanceRecvDue r ON rd.DueID = r.ID WHERE r.BuzType = {0} AND r.BuzID = {1} GROUP BY rd.RecvID);DELETE FROM IMS_FinanceRecvDetail WHERE DueID IN( SELECT ID FROM IMS_FinanceRecvDue WHERE BuzType = {0} AND BuzID = {1});DELETE FROM IMS_FinanceRecvDue WHERE BuzType = {0} AND BuzID = {1};"
					, (int)FinanceBuzType.加工订单
					, model.ID);
				#endregion
			}
			else
			{
				model.AddDate = dtNow;
				model.AddManID = sessionCurrent.UserID;
				model.AddManName = sessionCurrent.UserName;
				model.OrgID = sessionCurrent.OrgID;
				model.SNo = NextSNo();
				//model.StateNow = (int)MachiningState.提交;
				Add(model);
				if (model.SHDs.Any())
				{
					int[] ids = model.SHDs.Select(x => x.ID).ToArray();
					context.Database.ExecuteSqlRaw("UPDATE Sys_Attachment SET InfoID = {0} WHERE ID IN ({1})", model.ID, string.Join(",", ids));
				}
				if (model.DQZDs.Any())
				{
					int[] ids = model.DQZDs.Select(x => x.ID).ToArray();
					context.Database.ExecuteSqlRaw("UPDATE Sys_Attachment SET InfoID = {0} WHERE ID IN ({1})", model.ID, string.Join(",", ids));
				}
			}


			#region 处理应收款
			if (model.Total > 0)
			{
				var recvDue = new IMS_FinanceRecvDue
				{
					BuzType = (int)FinanceBuzType.加工订单,
					BuzID = model.ID,
					BuzSNo = model.SNo,
					RecvState = (int)FinancePayRecvState.未收,
					PartnerID = model.PartnerID,
					PartnerName = model.PartnerName,
					TotalRecvDue = model.Total,
					TotalRecved = 0,
					Stage = "",
					AddDate = dtNow,
					AddManID = sessionCurrent.UserID,
					AddManName = sessionCurrent.UserName,
					OrgID = sessionCurrent.OrgID,
					Comment = "新增加工订单自动生成",
					SNo = serviceFinanceRecvDue.NextSNo()
				};
				int dueID = serviceFinanceRecvDue.Add(recvDue);
				if (model.PreRecvTotal > 0)
				{
					var details = new List<IMS_FinanceRecvDetail>{
						new IMS_FinanceRecvDetail
						{
							DueID = dueID,
							DueSNo = recvDue.SNo,
							Recved = model.PreRecvTotal,
							DetailAddDate = dtNow,
							OrgID = model.OrgID,
							DueRecv = recvDue
						}
					};
					var recv = new IMS_FinanceRecv
					{
						ShareType = (int)FinanceShareType.不自动分配,
						PartnerID = model.PartnerID,
						PartnerName = model.PartnerName,
						RecvDate = dtNow,
						RecvWay = model.RecvWay,
						BillNo = null,
						Invoice = false,
						InvoiceNo = null,
						TotalRecv = model.PreRecvTotal,
						AddDate = dtNow,
						AddManID = sessionCurrent.UserID,
						AddManName = sessionCurrent.UserName,
						OrgID = model.OrgID,
						Details = details,
						Comment = "新增加工订单自动生成",
					};
					serviceFinanceRecv.AddOrUpdateWithinTrans(recv, sessionCurrent);
				}
			}
			#endregion
		}

		/// <summary>
		/// 删除具体操作
		/// </summary>
		/// <param name="id"></param>
		/// <param name="ip"></param>
		/// <param name="dtNow"></param>
		/// <param name="sessionCurrent"></param>
		protected void DeleteWithinTrans(int id, string ip, DateTime dtNow, UserSession sessionCurrent)
		{
			var modelOld = Get(id, true);
			SqlParameter[] paras = new SqlParameter[]{
				new SqlParameter("@ID",id),
			};

			////删除应收款
			serviceFinanceRecvDue.DeleteWithinTrans(FinanceBuzType.加工订单, id, ip, dtNow, sessionCurrent);

			Delete(modelOld);

			serviceSysLog.Add(sessionCurrent, ip, $"删除编号为[{modelOld.SNo}]的销售订单信息，原信息：", modelOld, dtNow);
		}

		/// <summary>
		/// 删除
		/// </summary>
		/// <param name="id"></param>
		/// <param name="sessionCurrent"></param>
		/// <returns></returns>
		public bool Delete(int id, UserSession sessionCurrent)
		{
			bool success = false;
			try
			{
				if (id <= 0)
				{
					throw new ArgumentNullException("id");
				}
				if (sessionCurrent == null)
				{
					throw new ArgumentNullException("sessionCurrent");
				}

				using (var trans = context.Database.BeginTransaction())
				{
					try
					{
						#region 事务具体操作
						DateTime dtNow = DateTime.Now;
						string ip = GetRequestIP();
						DeleteWithinTrans(id, ip, dtNow, sessionCurrent);
						#endregion

						trans.Commit();
					}
					catch (Exception ex)
					{
						trans.Rollback();
						throw ex.InnerException ?? ex;
					}
				}

				success = true;
			}
			catch (ArgumentNullException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (BuzException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.InnerException != null ? ex.InnerException.Message : ex.Message, ex);
			}
			return success;
		}

		/// <summary>
		/// 批量删除
		/// </summary>
		/// <returns></returns>
		public bool BatchDelete(int[] ids, UserSession sessionCurrent)
		{
			bool success = false;
			try
			{
				if (ids == null || ids.Length == 0)
				{
					throw new ArgumentNullException("ids");
				}
				if (sessionCurrent == null)
				{
					throw new ArgumentNullException("sessionCurrent");
				}

				using (var trans = context.Database.BeginTransaction())
				{
					try
					{
						#region 事务具体操作
						DateTime dtNow = DateTime.Now;
						string ip = GetRequestIP();

						foreach (int id in ids)
						{
							DeleteWithinTrans(id, ip, dtNow, sessionCurrent);
						}
						#endregion

						trans.Commit();
					}
					catch (Exception ex)
					{
						trans.Rollback();
						throw ex.InnerException ?? ex;
					}
				}

				success = true;
			}
			catch (ArgumentNullException ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw ex;
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.InnerException != null ? ex.InnerException.Message : ex.Message, ex);
			}
			return success;
		}

		/// <summary>
		/// 获取下一个流水号
		/// </summary>
		/// <returns></returns>
		public string NextSNo()
		{
			try
			{
				DateTime dtNow = DateTime.Now;
				string prefix = "XS" + DateTime.Now.ToString("yyyyMMdd");
				string maxSNo = context.Machining.Where(m => EF.Functions.Like(m.SNo, prefix + "%")).Max(m => m.SNo);
				int maxNo = 0;
				if (!string.IsNullOrEmpty(maxSNo))
				{
					int.TryParse(maxSNo.Substring(prefix.Length), out maxNo);
				}

				return prefix + (maxNo + 1).ToString().PadLeft(4, '0');
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				throw new BuzException(ex.Message, ex);
			}
		}
	}
}